package com.fwj.auth.service.user;

import com.alibaba.fastjson.JSONObject;
import com.fwj.auth.api.user.UserService;
import com.fwj.auth.dao.user.UserExtendAccountMapper;
import com.fwj.auth.dao.user.UserMapper;
import com.fwj.auth.entity.user.UserBaseInfo;
import com.fwj.auth.entity.user.UserExtendAccount;
import com.fwj.auth.model.BindInfo;
import com.fwj.auth.strategy.BingInfoStrategy;
import com.fwj.auth.strategy.RegisterStrategy;
import com.fwj.core.common.common.CommonUtils;
import com.fwj.core.common.common.CookieUtil;
import com.fwj.core.common.common.RedisUtil;
import com.fwj.core.common.constant.*;
import com.fwj.core.common.execption.CommonException;
import com.fwj.core.common.model.ResponseDTO;
import com.fwj.core.common.model.ResponseEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.List;

/**
 * @Author: fwj
 * @Data: 2022/4/13 18:57
 * @Version 1.0
 * @Description:
 */

@Service
public class UserServiceImpl implements UserService {
    //添加日志工厂
    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserExtendAccountMapper userExtendAccountMapper;

    @Override
    @Transactional
    public ResponseDTO saveUserExtendAccount(UserExtendAccount userExtendAccount, String identityCode) {
        ResponseDTO responseDTO = new ResponseDTO();
        try {
            //检测验证码是否有效
            if (!checkIdentityCodeRealness(userExtendAccount,identityCode)){
                throw new CommonException(ResponseEnum.IDENTITY_CODE_ERROR);
            }
            //构建用户账号登录信息
            UserExtendAccount execUser = buildUserExtendAccount(userExtendAccount);
            //构建用户账号基本信息
            UserBaseInfo userBaseInfo = buildUserBaseInfo();
            //保存用户账号基本信息
            userMapper.insertSelective(userBaseInfo);
            execUser.setUserId(userBaseInfo.getId());
            userExtendAccountMapper.insertSelective(execUser);
            return responseDTO.success(ResponseEnum.SUCCESS);
        } catch (CommonException e){
            LOGGER.error(e.toString());
            return responseDTO.fail(e.getResponseEnum());
        } catch (Exception e){
            LOGGER.error(e.toString());
            e.printStackTrace();
            return responseDTO.fail(ResponseEnum.SERVER_ERROR.getCode(),"账号注册失败");
        }
    }

    private boolean checkIdentityCodeRealness(UserExtendAccount userExtendAccount, String identityCode) {
        String key = CoreConstant.REGISTER + userExtendAccount.getValue();
        try {
            if (CommonUtils.isNotEmpty(identityCode)){
                //验证该账号是否在Redis有验证码
                if (RedisUtil.exists(key)){
                    String code = RedisUtil.getString(key);
                    if (CommonUtils.isNotEmpty(code) && identityCode.equals(code)){
                        RedisUtil.delKey(key);
                        return true;
                    }
                }
            }
            return false;
        } catch (Exception e) {
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }

    private UserExtendAccount buildUserExtendAccount(UserExtendAccount userExtendAccount) throws Exception{
        //构建用户账号
        UserExtendAccount retUser = new UserExtendAccount();
        //如果设置了密码则为密码加密
        if (CommonUtils.isNotEmpty(userExtendAccount.getPassword())){
            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            retUser.setPassword(bCryptPasswordEncoder.encode(userExtendAccount.getPassword()));
        }
        retUser.setIsLogin(true);
        retUser.setValue(userExtendAccount.getValue());
        retUser.setExtendType(userExtendAccount.getExtendType());
        retUser.setExtendTypeSub(userExtendAccount.getExtendTypeSub());
        retUser.setExtendDesc(userExtendAccount.getExtendDesc());
        retUser.setCreateTime(new Timestamp(System.currentTimeMillis()));
        retUser.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        retUser.setStatus(UserConstant.NORMAL);
        return retUser;
    }

    /**
     * 构建用户基本信息
     * */
    private UserBaseInfo buildUserBaseInfo() throws Exception{
        //生成用户编码
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setNumber(CommonUtils.generateUniqueNumber());
        userBaseInfo.setCreateTime(new Timestamp(System.currentTimeMillis()));
        userBaseInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        userBaseInfo.setStatus(UserConstant.NORMAL);
        return userBaseInfo;
    }

    @Override
    public boolean checkUserExists(UserExtendAccount userExtendAccount){
        List<UserExtendAccount> userExtendAccounts = getLoginInfo(userExtendAccount.getValue());
        if (CommonUtils.isNotEmpty(userExtendAccounts)){
            return true;
        }
        return false;
    }

    @Override
    public ResponseDTO logout(HttpServletRequest request){
        try {
            ResponseDTO responseDTO = new ResponseDTO();
            //获取登录会话信息
            String authSession = getAuthSession(request);
            if (RedisUtil.exists(authSession)){
                RedisUtil.delKey(authSession);
                responseDTO.success();
            }else {
                responseDTO.fail(ResponseEnum.USER_NO_LOGIN);
            }
            return responseDTO;
        } catch (Exception e){
            LOGGER.error(e.toString());
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }

    @Override
    public UserBaseInfo findUserByAccount(String account) {
        try {
            List<UserExtendAccount> userExtendAccounts = getLoginInfo(account);
            Example example = new Example(UserBaseInfo.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("id",userExtendAccounts.get(0).getUserId());
            criteria.andNotEqualTo("status",DataConstant.DELETED);
            UserBaseInfo userBaseInfo = userMapper.selectOneByExample(example);
            if (CommonUtils.isEmpty(userBaseInfo)){
                throw new CommonException(ResponseEnum.USER_NO_EXISTS);
            }
            return userBaseInfo;
        } catch (Exception e){
            LOGGER.error(e.toString());
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }

    @Override
    public ResponseDTO saveBindAccount(UserExtendAccount userExtendAccount, UserBaseInfo userBaseInfo) {
        try {
            //构建用户账号登录信息
            UserExtendAccount execUser = buildUserExtendAccount(userExtendAccount);
            execUser.setUserId(userBaseInfo.getId());
            //如果是邮箱则转化相应格式
            whenEmailConver(execUser,userExtendAccount);
            //获取扩展类型
            Example example = new Example(UserExtendAccount.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("userId",execUser.getUserId());
            criteria.andEqualTo("type",execUser.getExtendType());
            //查询之前有的账号数据，二度修改execUser
            UserExtendAccount ret = userExtendAccountMapper.selectOneByExample(example);
            if (CommonUtils.isNotEmpty(ret)){
                execUser.setIsLogin(ret.getIsLogin());
                execUser.setCreateTime(ret.getCreateTime());
                userExtendAccountMapper.updateByPrimaryKeySelective(execUser);
            }
            userExtendAccountMapper.insertSelective(execUser);
            return new ResponseDTO().success();
        } catch (Exception e){
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }

    private void whenEmailConver(UserExtendAccount execUser, UserExtendAccount userExtendAccount) {
        if (userExtendAccount.getValue().matches(RegExConstant.Email)){
            String suffix = userExtendAccount.getValue().split("@")[1];
            AccountConstant accountConstant = AccountConstant.getAccountType(suffix);
            execUser.setExtendType(CoreConstant.EMAIL);
            execUser.setExtendTypeSub(accountConstant.getTypeSub());
            execUser.setExtendDesc(accountConstant.getDescription());
        }
    }

    @Override
    public ResponseDTO getBindInfo(UserBaseInfo userBaseInfo) {
        try {
            //获取用户绑定信息
            List<UserExtendAccount> userExtendAccountList = getUserAllExtendInfoById(userBaseInfo.getId());
            //封装返回结果
            BindInfo bindInfo = buildBindInfo(userExtendAccountList);
            return new ResponseDTO().success().setData(bindInfo);
        } catch (Exception e){
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }

    /**
     * 向用户发送注册验证码
     * @param jsonObject
     */
    @Override
    public ResponseDTO registerIdentifyingCode(JSONObject jsonObject) {
        try {
            String type = jsonObject.getString("type");
            JSONObject requestMessage = jsonObject.getJSONObject("requestMessage");
            RegisterStrategy registerStrategy = RegisterStrategy.matchStrategy(type);
            if (CommonUtils.isNotEmpty(registerStrategy)){
                registerStrategy.execStrategy(requestMessage);
            }
            return new ResponseDTO<>().success();
        }catch (CommonException e){
          return new ResponseDTO().fail(e.getResponseEnum());
        } catch (Exception e) {
            return new ResponseDTO().fail();
        }
    }

    private BindInfo buildBindInfo(List<UserExtendAccount> userExtendAccountList) throws Exception {
        BindInfo bindInfo = new BindInfo();
        for (UserExtendAccount userExtendAccount : userExtendAccountList){
            BingInfoStrategy bingInfoStrategy = BingInfoStrategy.matchStrategy(userExtendAccount.getExtendType());
            if (CommonUtils.isNotEmpty(bingInfoStrategy)){
                bingInfoStrategy.execStrategy(bindInfo,userExtendAccount);
            }
        }
        return bindInfo;
    }

    private List<UserExtendAccount> getUserAllExtendInfoById(Long id) throws Exception{
        Example example = new Example(UserExtendAccount.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("userId",id);
        criteria.andEqualTo("status",DataConstant.NORMAL);
        return getUserAllExtendInfoByExample(example);
    }

    private List<UserExtendAccount> getUserAllExtendInfoByExample(Example example) throws Exception{
        return userExtendAccountMapper.selectByExample(example);
    }

    @Override
    public List<UserExtendAccount> getLoginInfo(String value){
        try {
            Example example = new Example(UserExtendAccount.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("value",value);
            criteria.andEqualTo("isLogin",true);
            criteria.andNotEqualTo("status",DataConstant.DELETED);
            List<UserExtendAccount> userExtendAccounts = userExtendAccountMapper.selectByExample(example);
            return userExtendAccounts;
        } catch (Exception e){
            LOGGER.error(e.toString());
            throw new CommonException(ResponseEnum.SERVER_ERROR);
        }
    }


    /**
     * @Description 获取登录信息
     * @Param: request
     * @Author fwj
     * @return java.lang.String
     * @Createtime 2022/4/11
     */
    private String getAuthSession(HttpServletRequest request) {
        String authSession = null;
        boolean isExist = false;
        //获取登录会话信息
        isExist =
                (   //获取Cookie中的会话信息
                         CommonUtils.isNotEmpty( ( authSession = CookieUtil.getCookie(request, CoreConstant.AUTH_SESSION) ) ) ? true : false
                )
                        ||  //没有获取到信息则继续执行
                        (   //获取header中的会话信息，此会话信息不该存在header中，为了方便测试用
                                CommonUtils.isNotEmpty( authSession = request.getHeader("authSession") ) ? true : false
                        )
        ;
        //如果未登录则抛出异常,终止流程
        if (!isExist){
            LOGGER.info("未登录");
            throw new CommonException(ResponseEnum.USER_NO_LOGIN);
        }
        return authSession;
    }
}
